<?php
// +----------------------------------------------------------------------
// | FileName: CommonService.php
// +----------------------------------------------------------------------
// | Date: 2022/6/19 21:19:29
// +----------------------------------------------------------------------
// | Author: 默毅 <moyi@mymoyi.cn>
// +----------------------------------------------------------------------
// | Notes: 
// +----------------------------------------------------------------------
	
	namespace App\Service\Library;
	
	use Hyperf\Di\Annotation\Inject;
	use Hyperf\HttpServer\Contract\RequestInterface;
	use Hyperf\Utils\ApplicationContext;
	
	class CommonService
	{
		#[Inject]
		protected RequestInterface $request;
		
		
		/**
		 * CURL发送Request请求,含POST和REQUEST
		 * @param string $url 请求的链接
		 * @param mixed $params 传递的参数
		 * @param string $method 请求的方法
		 * @param mixed $options CURL的参数
		 * @return array
		 */
		function sendRequest(string $url, $params = [], string $method = 'POST', $options = []): array
		{
			$method = strtoupper($method);
			$protocol = substr($url, 0, 5);
			$query_string = is_array($params) ? http_build_query($params) : $params;
			
			$ch = curl_init();
			$defaults = [];
			
			$defaults[CURLOPT_HEADER] = false;
			$defaults[CURLOPT_USERAGENT] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.98 Safari/537.36";
			$defaults[CURLOPT_FOLLOWLOCATION] = true;
			$defaults[CURLOPT_RETURNTRANSFER] = true;
			$defaults[CURLOPT_CONNECTTIMEOUT] = 60 * 10;
			$defaults[CURLOPT_TIMEOUT] = 60 * 10;
			
			
			if ('GET' == $method) {
				$geturl = $query_string ? $url . (stripos($url, "?") !== false ? "&" : "?") . $query_string : $url;
				$defaults[CURLOPT_URL] = $geturl;
			} else {
				$defaults[CURLOPT_URL] = $url;
				if ($method == 'POST') {
					$defaults[CURLOPT_POST] = 1;
				} else {
					$defaults[CURLOPT_CUSTOMREQUEST] = $method;
				}
				$defaults[CURLOPT_POSTFIELDS] = $params;
			}
			
			
			curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
			
			if ('https' == $protocol) {
				$defaults[CURLOPT_SSL_VERIFYPEER] = false;
				$defaults[CURLOPT_SSL_VERIFYHOST] = false;
			}
			
			curl_setopt_array($ch, (array)$options + $defaults);
			
			$ret = curl_exec($ch);
			$err = curl_error($ch);
			if (false === $ret || !empty($err)) {
				$errno = curl_errno($ch);
				$info = curl_getinfo($ch);
				curl_close($ch);
				return [
					'ret' => false,
					'errno' => $errno,
					'msg' => $err,
					'info' => $info,
				];
			}
			curl_close($ch);
			return [
				'ret' => true,
				'data' => @(array)json_decode($ret, true),
				'msg' => $ret,
			];
		}
		
		
		/**
		 * 能用的随机数生成
		 * @param string $type 类型 alpha/alnum/numeric/nozero/unique/md5/encrypt/sha1
		 * @param int $len 长度
		 * @return string
		 */
		public function random(string $type = 'alnum', int $len = 8)
		{
			switch ($type) {
				case 'alpha':
				case 'alnum':
				case 'numeric':
				case 'nozero':
					switch ($type) {
						case 'alpha':
							$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
							break;
						case 'alnum':
							$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
							break;
						case 'numeric':
							$pool = '0123456789';
							break;
						case 'nozero':
							$pool = '123456789';
							break;
					}
					return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
				case 'unique':
				case 'md5':
					return md5(uniqid(mt_rand()));
				case 'encrypt':
				case 'sha1':
					return sha1(uniqid(mt_rand(), true));
				default:
					return sprintf(
						'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
						mt_rand(0, 0xffff),
						mt_rand(0, 0xffff),
						mt_rand(0, 0xffff),
						mt_rand(0, 0x0fff) | 0x4000,
						mt_rand(0, 0x3fff) | 0x8000,
						mt_rand(0, 0xffff),
						mt_rand(0, 0xffff),
						mt_rand(0, 0xffff)
					);
			}
		}
		
		
		function getRealIp(): string
		{
			$request = ApplicationContext::getContainer()->get(RequestInterface::class);
			$headers = $request->getHeaders();
			if (isset($headers['x-forwarded-for'][0]) && !empty($headers['x-forwarded-for'][0])) {
				return $headers['x-forwarded-for'][0];
			} elseif (isset($headers['x-real-ip'][0]) && !empty($headers['x-real-ip'][0])) {
				return $headers['x-real-ip'][0];
			}
			$serverParams = $request->getServerParams();
			return $serverParams['remote_addr'] ?? '';
		}
		
		function saveBase64File($base64 = null, $suffix = 'png'): bool|string
		{
			try {
				if (!$base64) return false;
				$save_key = '/uploads/{ymd}/{size}_{md5}{.suffix}';
				$replaceArr = [
					'{ymd}' => date("Ymd"),
					'{md5}' => md5($base64),
					'{size}' => mb_strlen($base64),
					'{time}' => time(),
					'{.suffix}' => $suffix ? '.' . $suffix : '',
				];
				$save_key = str_replace(array_keys($replaceArr), array_values($replaceArr), $save_key);
				$destDir = BASE_PATH . '/' . substr($save_key, 0, strripos($save_key, '/') + 1);
				$file_path = BASE_PATH . '/' . $save_key;
				// 目标文件夹不存在就新建一个
				if (!is_dir($destDir)) {
					@mkdir($destDir, 0755, true);
				}
				$a = explode(',', $base64);
				file_put_contents($file_path, base64_decode(end($a)));
				return $save_key;
			} catch (\Exception) {
				return false;
			}
		}
		
		function saveOSS($file, $path): bool|string
		{
			$accessKeyId = env('aliyun_key_id');
			$accessKeySecret = env('aliyun_key_secret');
			$cdn = env('aliyun_oss_cdn');
			$bucket = env('aliyun_oss_bucket');
			$cdn = env('aliyun_oss_cdn');
			// 空间
			$bucket = 'moyi-tiktok';
			// 上传PUT
			$method = 'PUT';
			// 图片位置
			$path = $path ?? '/exampledir/test' . random_int(0, 9999999) . '.png';
			// 图片大小
			$file_size = sprintf('%u', filesize($file));
			// 都是https
			$scheme = 'https://';
			// 区域服务器域名
			$endpoint = "oss-cn-beijing.aliyuncs.com";
			$headers = [
				'Accept-Encoding' => '',
				'Content-Type' => 'image/png',
				'Date' => gmdate('D, d M Y H:i:s \G\M\T'),
				'Host' => ($bucket . '.') . $endpoint
			];
			$requestUrl = $scheme . $headers['Host'] . $path;
			$signable_resource = "/{$bucket}{$path}";
			$string_to_sign = "{$method}\n{$headers['Accept-Encoding']}\n{$headers['Content-Type']}\n{$headers['Date']}\n{$signable_resource}";
			$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $accessKeySecret, true));
			$headers['Authorization'] = "OSS {$accessKeyId}:{$signature}";
			$header = [];
			foreach ($headers as $index => $val) {
				$header[] = "{$index}:{$val}";
			}
			$ret = $this->sendRequest($requestUrl, '', $method, [
				CURLOPT_HTTPHEADER => $header,
				CURLOPT_POSTFIELDS => fread(fopen($file, 'r'), (int)$file_size)
			]);
			if ($ret) {
				return $cdn . $path;
			}
			return false;
		}
		
		
		function aliyunCheckImg($img_url)
		{
			
			try {
				$accessKeyId = env('aliyun_key_id');
				$accessKeySecret = env('aliyun_key_secret');
				$scheme = 'https://';
				$endpoint = 'green-cip.cn-beijing.aliyuncs.com';
				$img_arr = [
					'imageUrl' => $img_url
				];
				$param = [
					'Service' => 'baselineCheck',
					'ServiceParameters' => json_encode($img_arr)
				];
				$param = json_encode($param);
				$headers = [
					'host' => $endpoint,
					'x-acs-version' => '2022-03-02',
					'x-acs-action' => 'ImageModeration',
					'x-acs-date' => gmdate('Y-m-d\\TH:i:s\\Z'),
					// 官方SDK给时间戳一顿加密为了啥？简单生成一个随机数不好吗？
					'x-acs-signature-nonce' => md5((string)microtime(true) . $this->random()),
					'content-type' => 'application/json; charset=utf-8',
					'x-acs-content-sha256' => bin2hex(hash('sha256', $param, true))
				];
				
				// 排序
				ksort($headers);
				$canonicalHeaderString = '';
				foreach ($headers as $k => $v) {
					$canonicalHeaderString .= $k . ':' . $v . "\n";
				}
				$sign = [
					'POST',
					'/',
					'',
					$canonicalHeaderString,
					implode(';', array_keys($headers)),
					$headers['x-acs-content-sha256']
				];
				$signatureAlgorithm = 'ACS3-HMAC-SHA256';
				$signature = bin2hex(hash_hmac('sha256', "{$signatureAlgorithm}\n" . bin2hex(hash('sha256', implode("\n", $sign), true)), $accessKeySecret, true));
				$headers['Authorization'] = $signatureAlgorithm . ' Credential=' . $accessKeyId . ',SignedHeaders=' . implode(';', array_keys($headers)) . ',Signature=' . $signature;
				$header = [];
				foreach ($headers as $index => $val) {
					$header[] = "{$index}:{$val}";
				}
				$requestUrl = $scheme . $endpoint;
				$method = 'POST';
				$ret = $this->sendRequest($requestUrl, $param, $method, [
					CURLOPT_HTTPHEADER => $header,
				]);
				if ($ret['ret']) {
					if (@$ret['data']['Data']['Result']) {
						return $this->checkImgTag($ret['data']['Data']['Result']);
					}
				}
				print_r(['ret'=>$ret['ret']]);
				return false;
			} catch (\Exception $exception) {
				print_r(['审核出错',$exception]);
				return false;
			}
		}
		
		function checkImgTag($result)
		{
			$baselineCheck_tag = [
				'pornographic_adultContent' => '疑似含有成人色情内容。',
				'pornographic_adultContent_tii' => '图中文字疑似含有色情内容。',
				'sexual_suggestiveContent' => '疑似含有疑似低俗或性暗示内容。',
				'sexual_partialNudity' => '疑似含有包含肢体裸露或性感内容',
				'sexual_affectionDisplay' => '疑似含有亲密行为的内容。',
				'political_historicalNihility' => '疑似含有历史虚无内容。',
				'political_historicalNihility_tii' => '图中文字疑似含有历史虚无信息。',
				'political_politicalFigure' => '疑似含有政治人物的内容。',
				'political_politicalFigure_name_tii' => '图中文字疑似含有领导人姓名。',
				'political_politicalFigure_metaphor_tii	' => '图中文字疑似含有对主要领导人的代称、暗喻。',
				'political_prohibitedPerson' => '疑似含有不宜宣传的人物的内容。',
				'political_prohibitedPerson_tii' => '图中文字疑似含有落马官员的姓名。',
				'political_taintedCelebrity' => '疑似含有重大负面的公众人物的内容。',
				'political_taintedCelebrity_tii	' => '图中文字疑似含有劣迹艺人的姓名。',
				'political_flag' => '疑似含有国家或地区旗帜。',
				'political_map' => '疑似含有中国地图。',
				'political_TVLogo' => '疑似含有特定电视台台标。',
				'political_outfit' => '疑似含有公务服装。',
				'political_religion_tii' => '图中文字疑似含有宗教元素或者信息。',
				'political_racism_tii' => '图中文字疑似含有歧视的表达内容。',
				'violent_explosion' => '疑似含有烟火类内容元素。',
				'violent_armedForces' => '疑似含有武装元素。',
				'violent_crowding' => '疑似含有人群聚集元素。',
				'violent_gunKnives' => '疑似含有刀具、枪支等内容',
				'violent_gunKnives_tii' => '图中文字疑似含枪支刀具的描述。',
				'violent_horrificContent' => '疑似含有惊悚、血腥等内容。',
				'violent_horrific_tii' => '图中文字疑似描述暴力、恐怖的内容。',
				'contraband_drug' => '含有疑似毒品等内容。',
				'contraband_drug_tii' => '图中文字疑似描述违禁毒品。',
				'contraband_gamble' => '含有疑似赌博等内容。',
				'contraband_gamble_tii' => '图中文字疑似描述赌博行为。',
			];
			$ret = '';
			print_r(['$result'=>$result]);
			foreach ($result as $item) {
				print_r(['$item'=>$item]);
				if (@$baselineCheck_tag[$item['Label']]) {
					print_r(['$baselineCheck_tag'=>$baselineCheck_tag[$item['Label']]]);
					$ret = $ret . $baselineCheck_tag[$item['Label']];
				}
			}
			
			return $ret == '' ? 'normal' :$ret;
		}
	}